# encoding=utf-8

"""SaveService.py
    - 用于批量数据存储的类，最开始会像常规方法一样存储图片，
    - 后续会用上数据库，管理用户上传的图片信息
"""
import json
import os
import flask
import cv2 as cv
import numpy as np
from PIL import Image
import traceback

from seg_system import ApplicationConfig
from seg_common.FileService import DirMakeFactory
from seg_common.Paser import ParserTools
from seg_common.LoggingService import ConsoleService
from seg_common.Annotation import CommonAnnotation
from seg_common.Exception import *


class SaveService(DirMakeFactory):
    def __init__(self):
        super(SaveService, self).__init__()
        self.NORMAL_0 = ""
        self.NORMAL_1 = ""
        self.NORMAL_1_1 = ""  # 2022.9.15增加的细胞分割
        self.NORMAL_2 = ""
        self.NORMAL_2_1 = ""
        self.NORMAL_3 = ""

        self.ENHANCE_0 = ""
        self.ENHANCE_1 = ""
        self.ENHANCE_1_1 = ""
        self.ENHANCE_2 = ""
        self.ENHANCE_2_1 = ""
        self.ENHANCE_3 = ""

        self.NORMAL_TMP = ""  # 需求变更，需要创建临时目录，合并分割的结果到原图
        self.ENHANCE_TMP = ""

    """ ---------------  公开函数 ------------------------------"""
    def img_change_format(self, img_from, img_save_path):
        d = {}
        try:
            # pil method
            image = Image.open(img_from)
            image = image.convert('RGB')
            image = image.resize((384, 384), Image.ANTIALIAS)
            image.save(img_save_path)
            return
        except Exception as e:
            print(traceback.format_exc())
            d['pil_format_exception'] = str(e)

        try:
            # opencv method
            image = cv.imread(img_from, cv.IMREAD_COLOR)
            image = cv.resize(image, (384, 384))
            cv.imwrite(img_save_path, image)
            return
        except Exception as e:
            print(traceback.format_exc())
            d['opencv_format_exception'] = str(e)
            raise FormatFailException(json.dumps(d))

    def img_save(self, request: flask.Request, save_dir: str):
        user_name, token = ParserTools.parser_name_token_from_request(request)
        result, message = self.temp_dir_create(save_dir=save_dir, user_name=user_name, token=token)

        if result:
            for each_file in request.files.getlist('image'):
                orin_name = each_file.filename
                name = orin_name.split(".")[0]
                modify_file_name = name + ".png"
                IMAGE_SAVE_PATH_TMP = os.path.join(self.NORMAL_0, orin_name)
                IMAGE_SAVE_PATH = os.path.join(self.NORMAL_0, modify_file_name)
                try:
                    # 这段代码不要动,很多人图片改个名字就上传了
                    # 导致接受到的图片后续直接读取失败
                    # 保存到文件是应为内存中莫名容易处理失败
                    # 使用PIL主要是它对各种图片的兼容性比opencv好
                    each_file.save(IMAGE_SAVE_PATH_TMP)
                    # image = Image.open(IMAGE_SAVE_PATH_TMP)
                    # image = image.convert('RGB')
                    # image.save(IMAGE_SAVE_PATH)
                    self.img_change_format(IMAGE_SAVE_PATH_TMP, IMAGE_SAVE_PATH)
                    assert os.path.exists(IMAGE_SAVE_PATH) is True
                    if IMAGE_SAVE_PATH_TMP != IMAGE_SAVE_PATH:
                        os.remove(IMAGE_SAVE_PATH_TMP)
                    # 这段代码就是强制转换为png图像，减少后续出问题的可能性
                    message.append({'name': each_file.filename, 'success': 'ok'})
                    ConsoleService.console_log("receive image:\n\t{}".format(IMAGE_SAVE_PATH))
                except Exception as e:
                    # 失败的文件需要删除
                    DirMakeFactory.remove_file(IMAGE_SAVE_PATH_TMP)
                    DirMakeFactory.remove_file(IMAGE_SAVE_PATH)
                    print(traceback.format_exc())
                    message.append({'name': each_file.filename, 'error': str(e)})
                    result = False
                    ConsoleService.console_log("receive image failed!:\n\t{}".format(IMAGE_SAVE_PATH))

        return result, message

    @CommonAnnotation.override()
    def path_init_with_request(self, request: flask.Request, save_dir: str = None):
        user_name, token = ParserTools.parser_name_token_from_request(request)
        return self.temp_dir_create(save_dir=save_dir, user_name=user_name, token=token)

    """ ---------------  工具函数 ------------------------------"""

    @CommonAnnotation.override()
    def path_init(self, **kwargs):
        save_dir, user_name, token = super().base_parser(**kwargs)
        if user_name and token:
            USER_FOLDER = os.path.join(ApplicationConfig.PathConfig.BASE_SAVE_PATH,
                                       user_name, token)
        else:
            USER_FOLDER = os.path.join(ApplicationConfig.PathConfig.BASE_SAVE_PATH,
                                       ApplicationConfig.PathConfig.DEFAULT_USER_NAME,
                                       ApplicationConfig.PathConfig.DEFAULT_USER_TOKEN)

        if save_dir:
            USER_FOLDER = os.path.join(save_dir, USER_FOLDER)

        NORMAL_FOLDER = os.path.join(USER_FOLDER, ApplicationConfig.PathConfig.NORMAL_SAVE_PATH)
        ENHANCE_FOLDER = os.path.join(USER_FOLDER, ApplicationConfig.PathConfig.ENHANCE_SAVE_PATH)

        self.NORMAL_0 = os.path.join(NORMAL_FOLDER, ApplicationConfig.PathConfig.ORIGIN_ZERO_FOLDER)
        self.NORMAL_1 = os.path.join(NORMAL_FOLDER, ApplicationConfig.PathConfig.ORIGIN_ONE_FOLDER)
        self.NORMAL_1_1 = os.path.join(NORMAL_FOLDER, ApplicationConfig.PathConfig.ORIGIN_ONE_SUB_FOLDER)
        self.NORMAL_2 = os.path.join(NORMAL_FOLDER, ApplicationConfig.PathConfig.ORIGIN_TWO_FOLDER)
        self.NORMAL_2_1 = os.path.join(NORMAL_FOLDER, ApplicationConfig.PathConfig.ORIGIN_TWO_SUB_FOLDER)
        self.NORMAL_3 = os.path.join(NORMAL_FOLDER, ApplicationConfig.PathConfig.ORIGIN_THREE_FOLDER)

        self.ENHANCE_0 = os.path.join(ENHANCE_FOLDER, ApplicationConfig.PathConfig.ORIGIN_ZERO_FOLDER)
        self.ENHANCE_1 = os.path.join(ENHANCE_FOLDER, ApplicationConfig.PathConfig.ORIGIN_ONE_FOLDER)
        self.ENHANCE_1_1 = os.path.join(ENHANCE_FOLDER, ApplicationConfig.PathConfig.ORIGIN_ONE_SUB_FOLDER)
        self.ENHANCE_2 = os.path.join(ENHANCE_FOLDER, ApplicationConfig.PathConfig.ORIGIN_TWO_FOLDER)
        self.ENHANCE_2_1 = os.path.join(ENHANCE_FOLDER, ApplicationConfig.PathConfig.ORIGIN_TWO_SUB_FOLDER)
        self.ENHANCE_3 = os.path.join(ENHANCE_FOLDER, ApplicationConfig.PathConfig.ORIGIN_THREE_FOLDER)

        self.NORMAL_TMP = os.path.join(NORMAL_FOLDER, ApplicationConfig.PathConfig.ORIGIN_NORMAL_TMP)
        self.ENHANCE_TMP = os.path.join(ENHANCE_FOLDER, ApplicationConfig.PathConfig.ORIGIN_ENHANCE_TMP)
        return USER_FOLDER

    @CommonAnnotation.override()
    def temp_dir_create(self, **kwargs):
        USER_FOLDER = self.path_init(**kwargs)
        if os.path.exists(self.NORMAL_0):
            # 提前截断，减少硬盘资源读取
            return True, [{'name': USER_FOLDER, 'success': 'ok'}]

        try:
            ApplicationConfig.PathConfig.make_dir(self.NORMAL_0)
            ApplicationConfig.PathConfig.make_dir(self.NORMAL_1)
            ApplicationConfig.PathConfig.make_dir(self.NORMAL_1_1)
            ApplicationConfig.PathConfig.make_dir(self.NORMAL_2)
            ApplicationConfig.PathConfig.make_dir(self.NORMAL_2_1)
            ApplicationConfig.PathConfig.make_dir(self.NORMAL_3)

            ApplicationConfig.PathConfig.make_dir(self.ENHANCE_0)
            ApplicationConfig.PathConfig.make_dir(self.ENHANCE_1)
            ApplicationConfig.PathConfig.make_dir(self.ENHANCE_1_1)
            ApplicationConfig.PathConfig.make_dir(self.ENHANCE_2)
            ApplicationConfig.PathConfig.make_dir(self.ENHANCE_2_1)
            ApplicationConfig.PathConfig.make_dir(self.ENHANCE_3)

            ApplicationConfig.PathConfig.make_dir(self.NORMAL_TMP)
            ApplicationConfig.PathConfig.make_dir(self.ENHANCE_TMP)
        except Exception as e:
            print(traceback.format_exc())
            return False, [{'name': USER_FOLDER, 'error': str(e)}]
        return True, [{'name': USER_FOLDER, 'success': 'ok'}]
